package com.kornero.auto.util.view;

import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class SWTInvocationHandler implements InvocationHandler {

    private static final Logger logger = LoggerFactory.getLogger(SWTInvocationHandler.class);

    /**
     * Method invocation result
     */
    private Object invocationResult = null;

    private final Composite source;

    public SWTInvocationHandler(final Composite source) {
        this.source = source;
    }

    @Override
    public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
        final RequiresSWT mark = method.getAnnotation(RequiresSWT.class);
        try {
            if (mark != null) {
                final Display display = source.getDisplay();

                // If we are currently in User-Interface thread.
                if (display.getThread() == Thread.currentThread()) {

                    return invocationResult = method.invoke(source, args);

                }
                final Runnable task = new Runnable() {
                    @Override
                    public void run() {
                        try {
                            invocationResult = method.invoke(source, args);
                        } catch (Exception ex) {
                            logger.error("invoke(): from UI thread", ex);
                            throw new RuntimeException(ex);
                        }
                    }
                };
                if (RequiresSWTPolicy.ASYNC.equals(mark.value())) {
                    display.asyncExec(task);
                } else {
                    display.syncExec(task);
                }
            } else {
                invocationResult = method.invoke(source, args);
            }
            return invocationResult;
        } catch (IllegalAccessException | InvocationTargetException e) {
            logger.error("invoke(): from current thread", e);
            throw new RuntimeException(e);
        }
    }
}
